/*
 * HSM Proxy Project.
 * Copyright (C) 2013 FedICT.
 * Copyright (C) 2013 Frank Cornelis.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see 
 * http://www.gnu.org/licenses/.
 */

package be.fedict.hsm.model.security;

import java.security.Principal;
import java.util.Map;
import java.util.Set;

import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class AdministratorLoginModule implements LoginModule {

	private static final Log LOG = LogFactory
			.getLog(AdministratorLoginModule.class);

	private Subject subject;

	private CallbackHandler callbackHandler;

	private String authenticatedAdministrator;

	private AdministratorSecurityBean administratorSecurityBean;

	public AdministratorLoginModule() {
		super();
		LOG.debug("constructor");
	}

	@Override
	public void initialize(Subject subject, CallbackHandler callbackHandler,
			Map<String, ?> sharedState, Map<String, ?> options) {
		LOG.debug("initialize");
		this.subject = subject;
		this.callbackHandler = callbackHandler;
		this.administratorSecurityBean = AdministratorSecurityBean
				.getInstance();
	}

	@Override
	public boolean login() throws LoginException {
		LOG.debug("login");
		NameCallback nameCallback = new NameCallback("username");
		PasswordCallback passwordCallback = new PasswordCallback("password",
				false);
		Callback[] callbacks = new Callback[] { nameCallback, passwordCallback };
		try {
			this.callbackHandler.handle(callbacks);
		} catch (Exception e) {
			throw new LoginException(e.getMessage());
		}
		String username = nameCallback.getName();
		String cardNumber = new String(passwordCallback.getPassword());
		String authenticatedAdministrator = this.administratorSecurityBean
				.getAuthenticatedAdministrator(username, cardNumber);
		if (null == authenticatedAdministrator) {
			throw new LoginException("invalid administrator: " + username);
		}
		this.authenticatedAdministrator = authenticatedAdministrator;
		return true;
	}

	@Override
	public boolean commit() throws LoginException {
		if (null != this.authenticatedAdministrator) {
			Set<Principal> principals = this.subject.getPrincipals();
			principals
					.add(new SimplePrincipal(this.authenticatedAdministrator));

			JBossRolesGroup rolesGroup = new JBossRolesGroup();
			rolesGroup.addMember(new SimplePrincipal(
					AdministratorRoles.ADMINISTRATOR));
			principals.add(rolesGroup);

			reset();
		}
		return true;
	}

	@Override
	public boolean abort() throws LoginException {
		logout();
		return true;
	}

	@Override
	public boolean logout() throws LoginException {
		reset();
		this.subject.getPrincipals().clear();
		return true;
	}

	private void reset() {
		this.authenticatedAdministrator = null;
	}
}
